﻿using System.Text;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

/// <summary>
///     数组类型定义，绑定到数组类型声明或声明文件中的数组类型绑定。
///     在声明语法中，对应 <code>Symbol[]</code> 格式的类型绑定。
///     其中，Symbol 的符号定义对应此符号的<see cref="OriginalDefinition" />属性。
/// </summary>
public class ArrayTypeSymbol : AbstractTypeSymbol, IEquatable<ArrayTypeSymbol>
{
    private readonly int[]? _boundaries;

    internal ArrayTypeSymbol(ITypeSymbol originalDefinition, int rank, int[]? length) :
        base(SymbolKinds.ArrayType, TypeKinds.Array)
    {
        OriginalDefinition = originalDefinition;
        Rank = rank;
        _boundaries = length;
    }

    public override string Name => ToString();

    public override string FullName => Name;


    /// <summary>
    ///     类型符号的维度数
    /// </summary>
    public int Rank { get; }


    /// <summary>
    ///     原始符号定义
    /// </summary>
    public override ITypeSymbol OriginalDefinition { get; }


    public override bool IsArrayType => true;


    /// <summary>
    ///     应改为调用<see cref="OriginalDefinition" />属性。
    /// </summary>
    /// <exception cref="NotSupportedException">此符号不支持此属性，将一直抛出错误。</exception>
    public override IDeclaration Declaration => throw new NotSupportedException();

    public bool Equals(ArrayTypeSymbol? other)
    {
        if (other is null)
        {
            return false;
        }

        if (ReferenceEquals(this, other))
        {
            return true;
        }

        int[]? thisBoundaries = GetBoundaries();
        int[]? otherBoundaries = other.GetBoundaries();

        return Rank == other.Rank &&
               OriginalDefinition.Equals(other.OriginalDefinition) &&
               ((thisBoundaries == null && otherBoundaries == null) ||
                (thisBoundaries != null && otherBoundaries != null &&
                 thisBoundaries.SequenceEqual(otherBoundaries)));
    }


    /// <summary>
    ///     数组类型定义中的宽度定义，可以忽略。如果某个宽度的维度没有定义，值是-1。
    /// </summary>
    public int[]? GetBoundaries()
    {
        return _boundaries;
    }


    /// <summary>
    ///     获取指定维度上的数组宽度定义。
    /// </summary>
    /// <param name="dim">数组维度数，0开始。</param>
    /// <returns>数组宽度，如果未定义，返回-1。</returns>
    public int GetBoundaries(int dim)
    {
        return _boundaries != null && _boundaries.Length > dim ? _boundaries[dim] : -1;
    }


    internal override bool TryAddMember(ISymbol member)
    {
        return false;
    }


    public override string ToString()
    {
        StringBuilder builder = new();
        builder.Append(OriginalDefinition.FullName);

        for (int i = 0; i < Rank; i++)
        {
            builder.Append('[');

            if (_boundaries != null && i < _boundaries.Length && _boundaries[i] >= 0)
            {
                builder.Append(_boundaries[i]);
            }

            builder.Append(']');
        }

        return builder.ToString();
    }

    public override bool Equals(object? obj)
    {
        return Equals(obj as ArrayTypeSymbol);
    }

    public override int GetHashCode()
    {
        return HashCode.Combine(Name, Rank, OriginalDefinition, _boundaries);
    }


    public static bool operator ==(ArrayTypeSymbol? left, ArrayTypeSymbol? right)
    {
        return left?.Equals(right) ?? right is null;
    }

    public static bool operator !=(ArrayTypeSymbol? left, ArrayTypeSymbol? right)
    {
        return !(left == right);
    }
}